import { AnyObject } from '@/ayaka'
import { BodyPartArrayType } from '@/utils/common'

/**
 * 角色枚举类型
 */
export enum CreepRoles {
    harvester = 'harvester',
    upgrader = 'upgrader',
    builder = 'builder',
    transporter = 'transporter',
    quicker = 'quicker',
    upgradeCarrier = 'upgradeCarrier',
    scout = 'scout',
    remoteGuard = 'remoteGuard',
    remoteHarvester = 'remoteHarvester',
    remoteCarrier = 'remoteCarrier',
    remoteReserver = 'remoteReserver',
    attacker = 'attacker',
    squadMember = 'squadMember',
    teamMember = 'teamMember',
    hugeCrowd = 'hugeCrowd',
    miner = 'miner',
    defender = 'defender',
    remoteBuilder = 'remoteBuilder',
    remoteClaimer = 'remoteClaimer',
    crossCarrier = 'crossCarrier',
    claimer = 'claimer',
    crossBuilder = 'crossBuilder',
    dpHarvester = 'dpHarvester',
    dpCarrier = 'dpCarrier',
}

/**
 * 角色默认优先级，越大越优先
 */
export enum CreepDefaultPriority {
    harvester = 15,
    upgrader = 25,
    builder = 20,
    transporter = 10,
    quicker = 9,
    upgradeCarrier = 25,
    scout = 30,
    remoteGuard = 17,
    remoteHarvester = 27,
    remoteCarrier = 27,
    remoteReserver = 26,
    attacker = 25,
    squadMember = 25,
    teamMember = 24,
    hugeCrowd = 25,
    miner = 28,
    defender = 13,
    remoteBuilder = 27,
    remoteClaimer = 26,
    crossCarrier = 26,
    claimer = 26,
    crossBuilder = 26,
    dpHarvester = 26,
    dpCarrier = 26,
}

/**
 * 自适应判断函数
 */
export type AdaptionJudgeFn = (room: MyRoom) => boolean

/**
 * 默认自适应判断函数
 */
export const defaultAdaptionJudge: AdaptionJudgeFn = (room) => {
    return !!room.memory.state.energy || room.energyAvailable >= room.energyCapacityAvailable
}

/**
 * 自适应后需要增加 memory
 */
export type AdaptionMemoryFn = (room: MyRoom, body: BodyPartConstant[]) => Partial<CreepMemory>

/**
 * 孵化任务
 */
export interface SpawnTask {
    /**
     * 角色名
     */
    role: CreepRoles
    /**
     * 身体部件元组的数组
     */
    body: BodyPartArrayType
    /**
     * 优先级
     */
    priority?: number
    /**
     * 是否允许自适应
     */
    adaption?: boolean
    /**
     * 是否采用默认的自适应判断函数
     */
    defaultAdaption?: boolean
    /**
     * 爬名
     */
    creepName?: string
    /**
     * 额外记忆
     */
    memory?: Partial<CreepMemory>
}

declare global {
    interface RoomMemory {
        /**
         * 孵化任务队列
         */
        spawnTasks: SpawnTask[]
    }

    interface CreepMemory {
        /**
         * 角色名
         */
        role: CreepRoles
        /**
         * 所属房间名
         */
        belong: string
        /**
         * 所属shard
         */
        shard: string
        /**
         * 工作状态
         */
        working?: boolean
        /**
         * 是否处于准备状态
         */
        ready?: boolean
        /**
         * 摸鱼时间，当该值大于0时，creep 不会执行工作
         */
        slack?: number
        /**
         * 总摸鱼时间
         */
        slackTotal?: number
        /**
         * 源id
         */
        sourceId?: string
        /**
         * 目标 id
         */
        targetId?: string
        /**
         * 身体部件统计
         */
        bodyParts?: Partial<Record<BodyPartConstant, number>>
        /**
         * 旅行时间
         */
        travelTime?: number
        /**
         * 任务 id
         */
        taskId?: string
        /**
         * 交谈数据
         */
        talked?: {
            [creepName: string]: number
        }
        /**
         * 额外数据
         */
        data?: AnyObject
    }

    interface PowerCreepMemory {
        role: 'default'
    }

    interface Room {
        // TODO: 无法直接找到函数的定义，并且函数名出错不会有提示
        /**
         * 获取孵化任务队列
         */
        getSpawnTasks(): SpawnTask[]
        /**
         * 按爬名搜索孵化任务
         */
        searchSpawnTaskByCreepName(creepName: string): SpawnTask | undefined
        /**
         * 按角色名搜索孵化任务
         */
        searchSpawnTaskByRole(role: CreepRoles): SpawnTask[]
        /**
         * 添加孵化任务
         */
        addSpawnTask(task: SpawnTask): string | false
        /**
         * 移除孵化任务
         */
        removeSpawnTask(task: SpawnTask): boolean
        /**
         * 获取spawn
         */
        getSpawn(): StructureSpawn[]
    }
}
